//================================================================================================================================
// Routines to set up the separate thread for the TCP connection and to set up the TCP client interface to TCPControl   
//================================================================================================================================
                        
#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <time.h>
#include "MCE.h"

#define DEFAULT_BUFLEN 512

static int connecting=0;        // Flag set to 1 if sockets are connecting
static int connected=0;         // Flag set to 1 if sockets are connected

typedef BOOL (WINAPI *QUERYFULLPROCESSIMAGENAME) (HANDLE hProcess, DWORD dwFlags, LPTSTR lpExeName, PDWORD lpdwSize);
QUERYFULLPROCESSIMAGENAME QueryFullProcessImageName;


//================================================================================================================================
// Routine to set up the TCP client interface to TCPControl   
//================================================================================================================================
DWORD Ttcp_client(LPVOID lpdwThreadParam)
{
    //----------------------
    // Declare and initialize variables.
    WSADATA wsaData;
    int iResult;
    SOCKET ConnectSocket;
    struct sockaddr_in clientService; 
    char recvbuf[DEFAULT_BUFLEN],str[128];
    int recvbuflen,i;
    
    // Initialise
    ConnectSocket = INVALID_SOCKET;
    recvbuflen = DEFAULT_BUFLEN;
    
    //----------------------
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != NO_ERROR) 
      { sprintf(str,"WSAStartup failed: %d", iResult); 
        Tlog("Ttcp_client",str);
        connecting=0;
        return 1; 
      }

    //----------------------
    // Create a SOCKET for connecting to server
    ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ConnectSocket == INVALID_SOCKET) 
      { sprintf(str,"Error at socket(): %ld", WSAGetLastError() ); 
        WSACleanup(); 
        Tlog("Ttcp_client",str);
        connecting=0; 
        return 1; 
      }

    //----------------------
    // The sockaddr_in structure specifies the address family,
    // IP address, and port of the server to be connected to.
    clientService.sin_family = AF_INET;
//    clientService.sin_addr.s_addr = inet_addr( TCPCONTROLLER_INET_ADDR );
//    clientService.sin_port = htons( TCPCONTROLLER_PORT_NUMBER );
    clientService.sin_addr.s_addr = inet_addr( getst(TAG_IPAddress) );
    clientService.sin_port = htons( geti(TAG_IPPort) );

    //----------------------
    // Connect to server.
    iResult = connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) );
    if ( iResult == SOCKET_ERROR) 
      {
        closesocket (ConnectSocket);
        sprintf(str,"Unable to connect to server: %ld", WSAGetLastError());
        WSACleanup();
        Tlog("Ttcp_client",str);
        connecting=0;
        return 1;
      }

    connected=1;
    // Receive and handle until the peer closes the connection
    do {
            recvbuflen = DEFAULT_BUFLEN;
            for (i=0; i<recvbuflen; i++) recvbuf[i]=0;
            iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
            if ( iResult > 0 ) { recvbuf[iResult]='\0'; MCE_decode(recvbuf); }
             else if ( iResult == 0 ) Tlog("Ttcp_client","Connection closed");
             else Tlog("Ttcp_client","recv failed:"); 
       } while( iResult > 0 );

    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    connected=0;
    connecting=0;
    return 0;
}

//================================================================================================================================
// external routine to start the MCE handler
// This initiates a separate thread to create the connection and handle the messages from Media Centre
//================================================================================================================================
extern int MCE_Init() 
{
   DWORD dwThreadId; 
   int i;
   
   Tlog("MCE_Init","Called");
   connecting=1;          // Set flag to inicate we are connecting to avoid another call to Init
   putdb(TAG_InitCalled,(double)clock()/CLOCKS_PER_SEC);       // Init start time
   
   if (CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&Ttcp_client,(LPVOID) &i,0,&dwThreadId) == NULL)
        { Tlog("MCE_Init","****Error Creating Thread****"); connecting=0; return(0); }
   else
        { Tlog("MCE_Init","Thread successfully created"); sleep(2000); return(1); }
}

//================================================================================================================================
// Check if thread has closed and re-initialise if it has (unless we are already trying!)
//================================================================================================================================
extern int MCE_check_for_reinit() 
{  double tdiff, start_time, end_time; int counter;

   start_time=getdb(TAG_InitCalled);
   end_time=(double)clock()/CLOCKS_PER_SEC;       // Counter time
   tdiff=end_time-start_time;                     // in seconds
   if ((start_time==0) || (tdiff > INIT_FREQUENCY))
     { if (connecting==0) 
         {
           if (MCE_dll_check_process("ehshell.exe")==1) { MCE_Init(); }
           else { putdb(TAG_InitCalled,(double)clock()/CLOCKS_PER_SEC); }      // Init start time
         }
     }
}

//================================================================================================================================
// external routine to start the MCE handler
// This initiates a separate thread to create the connection and handle the messages from Media Centre
//================================================================================================================================
extern int __stdcall MCE_dll_start() 
{
    int i;
    char status[80];
	DWORD dw;
	char buf[256];

    HMODULE lib=LoadLibrary(TEXT("Kernel32.dll"));

//    clear_tags();   
    puti(TAG_SessionFlag,0);
    putbi(TAG_RecordingStatus,0);

    if(MCE_Init()==0) { Tlog("MCE_dll_start","Cannot Connect"); strcpy(status,"Cannot Connect"); }
    else { strcpy(status,"Started"); }

    if (lib==NULL) { Tlog("MCE_dll_start","LoadLibrary Failed"); strcpy(status,"LoadLibrary Failed"); }
    else
      { QueryFullProcessImageName=(QUERYFULLPROCESSIMAGENAME)GetProcAddress(lib, "QueryFullProcessImageNameA");
        dw = GetLastError(); 
        if (dw!=0) 
          { FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                           NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) buf, 256, NULL );
            sprintf(status,"Error %d - %s\n",dw,buf);
            Tlog("MCE_dll_start",status);
          }
       }
     putst(TAG_SessionStatus,status);
}
